package com.apes.crm.business.service;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.apes.crm.business.model.InsuranceCompany;
import com.apes.crm.business.model.InsuranceCompanyDetail;
import com.apes.crm.business.repository.InsuranceCompanyDao;
import com.apes.crm.business.repository.InsuranceCompanyRepository;
import com.apes.framework.api.DomainService;
import com.apes.framework.api.SpringManager;
import com.apes.framework.jpa.spec.JpaDsl;
import com.apes.framework.jpa.spec.model.Filter;
import com.apes.framework.jpa.spec.model.Group;
import com.apes.framework.plugin.cache.Cache;
import com.apes.framework.plugin.esb.api.SimpleRequest;
import com.apes.framework.util.MapUtil;
import com.apes.scm.masterdata.area.model.Area;
import com.apes.scm.masterdata.area.repository.AreaRepository;
import com.apes.scm.masterdata.frame.model.Dept;
import com.apes.scm.masterdata.frame.model.Store;
import com.apes.scm.masterdata.frame.repository.DeptRepository;
import com.apes.scm.masterdata.frame.repository.StoreRepository;
import com.apes.scm.masterdata.party.model.PartyRole;
import com.apes.scm.masterdata.party.repository.PartyRoleRepository;
import com.apes.scm.rbac.model.Post;
import com.apes.scm.rbac.repository.PostRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @Classname InsuranceCompanyService
 * @Description TODO
 * @Date 2019/12/24 11:42
 * @Created by Administrator
 */
@Service("crmInsuranceCompanyService")
public class InsuranceCompanyService extends DomainService {
    @Autowired
    private InsuranceCompanyRepository insuranceCompanyRepository;
    @Autowired
    private AreaRepository areaRepository;
    @Autowired
    private StoreRepository storeRepository;
    @Autowired
    private DeptRepository deptRepository;
    @Autowired
    private Cache cache;
    @Autowired
    private InsuranceCompanyDao insuranceCompanyDao;

    public InsuranceCompany save(SimpleRequest request) {
        String id = request.get("id");
        InsuranceCompany insuranceCompany = request.getO(InsuranceCompany.class);
        InsuranceCompany data = insuranceCompanyRepository.findOne(JpaDsl.toCriteriaByEq("name",insuranceCompany.getName())).orElse(null);
        if (data != null) throw new RuntimeException("该保险公司" + insuranceCompany.getName() +"已存在系统,请勿重复定义!!!!");
        saveInsuranceCompanyDetails(insuranceCompany,request);
        resolveInsuranceCompanyItem(insuranceCompany);  //对省市处理
        changeCompany(insuranceCompany,request); // 所属公司设置
        return insuranceCompanyRepository.saveAndFlush(insuranceCompany);
    }


    /***
     * 功能： 修改
     * @param request
     * @return
     */
    public InsuranceCompany update(SimpleRequest request) {
        checkData(request);
        InsuranceCompany insuranceCompany = request.getO(InsuranceCompany.class);
        resolveInsuranceCompanyItem(insuranceCompany);  //对省市处理
        return insuranceCompanyRepository.saveAndFlush(insuranceCompany);
    }

    /***
     * 功能： 删除
     * @param request
     * @return
     * @throws RuntimeException
     */
    public InsuranceCompany delete(SimpleRequest request) throws RuntimeException {
        checkData(request);
        InsuranceCompany insuranceCompany = request.getO(InsuranceCompany.class);
        insuranceCompanyRepository.delete(insuranceCompany.getId());
        return insuranceCompany;
    }


    /**
     * 车险报案单页面的保险公司查询
     * @param request
     * @return
     */
    public Object findAllByCarAccident(SimpleRequest request){
        Dept dept = getDeptByCarAccident(request); // 获取门店
        JSONObject param = findAllByCarAccidentParam(request,dept); // 封装入参
        List ids = insuranceCompanyDao.findAllByCarAccident(param); // 查询
        List<InsuranceCompany> insuranceCompanies = new ArrayList<>();
        if (ids.size() > 0) insuranceCompanies = insuranceCompanyRepository.findAll(JpaDsl.toCriteria("id", "in", ids));
        insuranceCompanies = processByFindAllByCarAccident(dept,insuranceCompanies); // 若门店不为空，对查询数据的处理
        isNull(insuranceCompanies); // 查询不到数据时，前端提示
        return page(insuranceCompanies,request);
    }

    /**
     * 保险公司页面的查询
     * @param request
     * @return
     */
    public Object findAllByInsuranceCompany(SimpleRequest request){
        if (isFindAll(request)) {
            return invoke("crm.insuranceCompany.findAll",request.getJO());
        }
        // 获取公司与部门
        Post post = insuranceCompanyPost(request);
        PartyRole company = null;
        Dept dept = null;
        if (!Objects.isNull(post)){
            company = post.getCompany();
            dept = post.getDept();
        }
        JSONArray condition = request.getJO().getJSONArray("condition");
        // 封装查询条件  查询的所属公司为1001、1007、操作员所属公司
        Group group = wrapGroupByInsuranceCompany(company.getId(),condition);
        List<InsuranceCompany> insuranceCompanies = insuranceCompanyRepository.findAll(group.build(false));
        insuranceCompanies = processByDept(dept,insuranceCompanies);
        return page(insuranceCompanies,request);
    }

    /**
     * 根据门店信息的省/市排除
     * @param dept
     * @param insuranceCompanies
     * @return
     */
    private List<InsuranceCompany> processByDept(Dept dept, List<InsuranceCompany> insuranceCompanies){
        if (Objects.isNull(dept)) return insuranceCompanies;
        List<InsuranceCompany> result = new ArrayList<>();
        // 根据门店信息的省/市排除
        Store store = storeRepository.findAll(JpaDsl.toCriteria("dept.id", "EQ", dept.getId())).stream().findFirst().orElse(null);
        if (Objects.isNull(store)) throw new RuntimeException("无法根据门店查询到门店信息！");
        result = insuranceCompanies.stream().filter(insuranceCompany -> {
            int size = insuranceCompany.getInsuranceCompanyDetails().stream().filter(insuranceCompanyDetail -> {
                Area insuranceCompanyDetailCity = insuranceCompanyDetail.getCity();
                Area insuranceCompanyDetailProvince = insuranceCompanyDetail.getProvince();
                Area storeCity = store.getCity();
                Area storeProvince = store.getProvince();
                if (!Objects.isNull(insuranceCompanyDetailCity) && !Objects.isNull(insuranceCompanyDetailProvince) &&
                        !Objects.isNull(storeCity) && !Objects.isNull(storeProvince) &&
                        insuranceCompanyDetailCity.getId().equals(storeCity.getId()) && insuranceCompanyDetailProvince.getId().equals(storeProvince.getId())) {
                    return true;
                }
                return false;
            }).collect(Collectors.toList()).size();
            return size > 0 ? true : false;
        }).collect(Collectors.toList());
        return result;
    }

    public JSONObject findAllByCarAccidentParam(SimpleRequest request,Dept dept){
        JSONObject param = new JSONObject();
        if (!Objects.isNull(dept)) param.put("deptId",dept.getId());
        JSONObject jo = request.getJO();
        if (jo.containsKey("group")){
            // 文本框查询
            param.put("query","group");
            JSONObject group = (JSONObject) jo.getJSONObject("group").getJSONArray("groups").get(0);
            JSONObject filter = (JSONObject) group.getJSONArray("filters").get(0);
            String value = filter.getString("value");
            param.put("value",value);
        }else if(jo.containsKey("condition")){
            // 弹框查询
            param.put("query","condition");
            JSONArray condition = jo.getJSONArray("condition");
            condition.stream().forEach(item -> {
                JSONObject conditionItem = (JSONObject) item;
                String field = conditionItem.getString("field");
                String value = conditionItem.getString("value");
                param.put(field,value);
            });
        }
        return param;
    }

    private void changeRequest(SimpleRequest request) {
        JSONObject newRequest = request.getJO();
        if (!newRequest.containsKey("group")) return;
        JSONObject oldGroup = newRequest.getJSONObject("group");
        JSONArray filters = oldGroup.getJSONArray("filters");
        JSONObject newGroup = oldGroup.getJSONArray("groups").getJSONObject(0);
        newRequest.put("group",newGroup);
        request.setBody(newRequest.toJSONString());
    }

    private Dept getDeptByCarAccident(SimpleRequest request){
        Dept dept = null; // 获取门店
        if (request.getJO().containsKey("dept") && !Objects.isNull(request.get("dept"))){
            dept = JSONObject.parseObject(JSONObject.toJSONString(request.get("dept")), Dept.class);
            dept = deptRepository.findOne(dept.getId());
        }
        if (request.getJO().containsKey("group")){
            JSONObject group = request.getJO().getJSONObject("group");
            JSONArray filters = group.getJSONArray("filters");
            for (Object item : filters) {
                JSONObject filter = (JSONObject) item;
                if (filter.containsKey("field") && "deptId".equals(filter.getString("field"))){
                    dept = deptRepository.findOne(filter.getString("value"));
                    break;
                }
            }
        }
        return dept;
    }

    private boolean isFindAll(SimpleRequest request) {
        JSONObject jo = request.getJO();
        if (!jo.containsKey("platform")) return true;
        String platform = jo.getString("platform");
        return platform.equals("zt");
    }

    /**
     * 保险公司页面明细添加时追加行
     * @param request
     * @return
     */
    public Object rowDate(SimpleRequest request){
        Store store = storeByRequest(request);
        return MapUtil.mapper("city",store.getCity(),
                "client", SpringManager.getBean(PartyRoleRepository.class).findOne("C0004457"),
                "renderAddr",store.getProvince().getName() + " / " + store.getCity().getName(),
                "sort",request.get("sort"));
    }

    private Store storeByRequest(SimpleRequest request){
        Dept dept = getDept(request);
        if (Objects.isNull(dept)) throw new RuntimeException("无法获取当前门店！");
        Store store = storeRepository.findAll(JpaDsl.toCriteria("dept.id", "EQ", dept.getId())).stream().findFirst().orElse(null);
        if (Objects.isNull(store)) throw new RuntimeException("根据门店查询不到门店信息！");
        return store;
    }

    /**
     * 判断当前角色是否有保险公司的权限
     * @param request
     * @return
     */
    public Object checkPermissions(SimpleRequest request){
        String id = request.getPostId();
        String platform = request.get("platform");
        if (Objects.isNull(id)) throw new RuntimeException("无法获取当前本地角色！");

        Map menuAuthCache = (Map) cache.get("menuAuthCache", id);
        if (Objects.isNull(menuAuthCache)) return false;
        List<String> menuIds = null;
        List menuList = null;
        if ("zt".equals(platform)){
            menuIds = new ArrayList<>(Arrays.asList("17", "28", "2066"));
            menuList = (List)menuAuthCache.get("platformSystem");
        }else{
            menuIds = new ArrayList<>(Arrays.asList("42", "57", "4679"));
            menuList = (List)menuAuthCache.get("merchantSystem");
        }

        return checkPermissions(menuList,menuIds);
    }

    private boolean checkPermissions(List menuList,List menuIds){
        if (menuIds.size() == 0) return true;
        String id = (String)menuIds.get(0);
        for (Object o : menuList) {
            Map menuItem = (Map)o;
            if (menuItem.containsKey("id") && id.equals(menuItem.get("id").toString())) {
                menuIds.remove(0);
                List children = (List) menuItem.get("children");
                return checkPermissions(children,menuIds);
            }
        }
        return false;
    }

    private Dept getDept(SimpleRequest request){
        Post post = SpringManager.getBean(PostRepository.class).findOne(request.getPostId());
        if (Objects.isNull(post)) return null;
        return post.getDept();
    }

    private void checkData(SimpleRequest request) {
        String id = request.get("id");
        long versions = (int) request.get("version"); // 获取当前请求的版本信息
        InsuranceCompany insuranceCompany = insuranceCompanyRepository.findOne(id);
        if (insuranceCompany == null) throw new RuntimeException("保险公司【" + id + "】在系统中不存在。");
        if (insuranceCompany.getVersion() != versions) throw new RuntimeException("记录已更新或已删除，请重新提交！");  // 用于判断当前版本是否被修改
    }

    /***
     * 处理省/市地址
     */
    private void resolveInsuranceCompanyItem(InsuranceCompany insuranceCompany) {
        Map<Area,Area> map = new HashMap<>();
        insuranceCompany.getInsuranceCompanyDetails().stream().forEach(insuranceCompanyItem -> {
            if( insuranceCompanyItem.getCity() == null ) return;
            Area regCity = insuranceCompanyItem.getCity();// 当前城市
            String regCityId = regCity.getParent(); //当前城市的省市编码
            Area regProvince = areaRepository.findOne(regCityId); //当前省份
            for (Map.Entry<Area,Area> entry : map.entrySet()){
                if (entry.getKey() == regProvince && entry.getValue() == regCity){
                    map.clear();
                    throw new RuntimeException("该保险公司在" + regProvince.getName() + regCity.getName() + "已存在相关信息");
                }
            }
            map.put(regProvince,regCity);
            insuranceCompanyItem.setCity(regCity); // 注册地址城市
            insuranceCompanyItem.setProvince(regProvince); //注册地址.省份
        });
    }

    /**
     * 设置保险公司的所属公司为操作员的所属公司
     * @param insuranceCompany
     * @param request
     */
    private void changeCompany(InsuranceCompany insuranceCompany,SimpleRequest request){
        PartyRole company = getCompany(request);
        if (Objects.isNull(company)) throw new RuntimeException("未查询到操作员本地角色的公司！");
        insuranceCompany.setCompany(company);
    }

    private PartyRole getCompany(SimpleRequest request){
        String postId = request.getPostId();
        if (Objects.isNull(postId)) return null;
        Post post = SpringManager.getBean(PostRepository.class).findOne(postId);
        return post.getCompany();
    }

    private Post insuranceCompanyPost(SimpleRequest request){
        String postId = request.getPostId();
        if (Objects.isNull(postId)) return null;
        return SpringManager.getBean(PostRepository.class).findOne(postId);
    }

    private List<InsuranceCompany> processByFindAllByCarAccident(Dept dept,List<InsuranceCompany> insuranceCompanies){
        if (Objects.isNull(dept)) return insuranceCompanies;
        List<InsuranceCompany> result = new ArrayList<>();
        // 根据门店信息的省/市排除
        result = processByDept(dept,insuranceCompanies);
        // 查询不到数据，根据部门的所属公司进行查询
        if (result.size() <= 0 && !Objects.isNull(dept.getCompany())){
            result = insuranceCompanyRepository.findAll(JpaDsl.toCriteria("company.id","EQ",dept.getCompany().getId()));
        }
        return result;
    }

    private void isNull(List<InsuranceCompany> insuranceCompanies){
        if (insuranceCompanies.size() > 0) return;
        InsuranceCompany insuranceCompany = new InsuranceCompany();
        insuranceCompany.setId("查无数据");
        insuranceCompany.setName("查无数据");
        insuranceCompanies.add(insuranceCompany);
    }

    private Group wrapGroup(SimpleRequest request){
        JSONObject jo = request.getJO();
        Group group = new Group();
        // 查询所属公司为1001或1007的
        List<Map> filters = Arrays.asList(MapUtil.mapper("field", "company.id", "operator", "IN", "value", Arrays.asList("1001", "1007")));
        group = createGroup(filters,"and",null);
        // 弹框查询条件
        if (jo.containsKey("condition") && jo.getJSONArray("condition").size() > 0){
            JSONArray condition = jo.getJSONArray("condition");
            group.addGroup(createGroup(condition,"and",null));
        }
        // 文本框查询条件
        if (jo.containsKey("group")){
            JSONObject groupJO = jo.getJSONObject("group");
            group.addGroup(createGroup(groupJO.getJSONArray("filters"),groupJO.getString("operator"),null));
        }
        return group;
    }

    private Group wrapGroupByInsuranceCompany(String companyId,JSONArray condition){
        Group group = null;
        if (condition.size() > 0){
            group = createGroup(condition, "and", null);
        }
        // 查询所属公司为1001，1007，用户所属公司
        List<Map> filters = Arrays.asList(MapUtil.mapper("field", "company.id", "operator", "IN", "value", Arrays.asList("1001", "1007",companyId)));
        if (Objects.isNull(group)){
            group = createGroup(filters,"or",null);
        }else{
            group.addGroup(createGroup(filters,"or",null));
        }
        return group;
    }

    private Page page(List<InsuranceCompany> resultList,SimpleRequest request){
        // 数据分页
        Pageable pageable = PageRequest.of(request.get("page"), request.get("size"));
        int fromIndex = pageable.getPageSize()*pageable.getPageNumber();
        int toIndex = pageable.getPageSize()*(pageable.getPageNumber()+1);
        if(toIndex > resultList.size()) toIndex = resultList.size();
        List<InsuranceCompany> current = resultList.subList(fromIndex,toIndex);
        return new PageImpl<InsuranceCompany>(current, pageable, resultList.size());
    }

    private Group createGroup(List filters,String operator,Group groups){
        Group group = new Group();
        if (!Objects.isNull(filters) && filters.size() > 0) group.addFilters(createFilter(filters));
        if (!Objects.isNull(operator)) group.setOperator(operator);
        if (!Objects.isNull(groups)) group.addGroup(groups);
        return group;
    }

    private List<Filter> createFilter(List filterMapList){
        List<Filter> filters = new ArrayList<>();
        for (Object o : filterMapList) {
            JSONObject filterJO = JSONObject.parseObject(JSONObject.toJSONString(o));
            filters.add(new Filter(filterJO.getString("field"),filterJO.get("value"),filterJO.getString("operator"),null));
        }
        return filters;
    }

    private void saveInsuranceCompanyDetails(InsuranceCompany insuranceCompany,SimpleRequest request){
        if (insuranceCompany.getInsuranceCompanyDetails().size() > 0
            || (!Objects.isNull(insuranceCompany.getSourcesType()) && !insuranceCompany.getSourcesType().equals("门店数据"))) {
            return;
        }
        List<InsuranceCompanyDetail> insuranceCompanyDetails = new ArrayList<>();
        InsuranceCompanyDetail insuranceCompanyDetail = new InsuranceCompanyDetail();
        Store store = storeByRequest(request);
        insuranceCompanyDetail.setCity(store.getCity());
        insuranceCompanyDetail.setClient(SpringManager.getBean(PartyRoleRepository.class).findOne("C0004457"));
        insuranceCompanyDetail.setInsuranceCompany(insuranceCompany);
        insuranceCompanyDetails.add(insuranceCompanyDetail);
        insuranceCompany.setInsuranceCompanyDetails(insuranceCompanyDetails);
    }
}
